import pandas as pd
import socket
import telnetlib
from datetime import datetime
import re

"""
使用该脚本telnet测试网络服务端口，需要先安装对应的模块：pip install pandas openpyxl telnetlib
"""

def expand_ip_range(ip_str):
    """
    展开IP地址范围，支持单个IP、IP段和逗号分隔的多个IP/段
    
    Args:
        ip_str (str): IP地址字符串，如 "192.168.1.11-20" 或 "192.168.1.11-20,192.168.1.100"
    
    Returns:
        list: 展开后的IP地址列表
    """
    ip_list = []
    
    # 按逗号分割多个地址项
    items = ip_str.split(',')
    
    for item in items:
        item = item.strip()
        if '-' in item and '.' in item:
            # 处理类似 192.168.1.11-20 的格式
            parts = item.split('.')
            last_part = parts[-1]
            
            if '-' in last_part:
                # 最后一段是范围
                start_end = last_part.split('-')
                start = int(start_end[0])
                end = int(start_end[1])
                
                # 构造基础IP前缀
                prefix = '.'.join(parts[:-1]) + '.'
                
                # 生成范围内的所有IP
                for i in range(start, end + 1):
                    ip_list.append(prefix + str(i))
            else:
                # 单个IP地址
                ip_list.append(item)
        else:
            # 单个IP地址
            ip_list.append(item)
    
    return ip_list

def expand_ports(port_str):
    """
    展开端口列表
    
    Args:
        port_str (str): 端口字符串，如 "80,443,8443,9943"
    
    Returns:
        list: 端口列表
    """
    ports = []
    
    # 按逗号分割端口
    port_items = port_str.split(',')
    
    for port_item in port_items:
        port_item = port_item.strip()
        if port_item.isdigit():
            ports.append(int(port_item))
    
    return ports

def check_port_connectivity(host, port, timeout=5):
    """
    使用telnet检查主机端口连通性
    
    Args:
        host (str): 目标主机地址
        port (int): 目标端口号
        timeout (int): 超时时间(秒)
    
    Returns:
        str: 连接结果 ('Success' 或 'Failed')
    """
    try:
        # 创建telnet连接
        tn = telnetlib.Telnet(host, port, timeout)
        tn.close()
        return 'Success'
    except Exception as e:
        return f'Failed: {str(e)}'

def validate_network_from_excel(excel_file):
    """
    从Excel文件读取网络地址信息并验证连通性
    
    Args:
        excel_file (str): Excel文件路径
    """
    try:
        # 读取Excel文件
        df = pd.read_excel(excel_file)
        
        # 检查必要的列是否存在
        if '目的地址' not in df.columns or '目的端口' not in df.columns:
            raise ValueError("Excel文件必须包含A列(目的地址)和B列(目的端口)")
        
        # 准备结果存储
        results = []
        
        # 遍历每一行进行网络验证
        for index, row in df.iterrows():
            source_addr_str = str(row['目的地址'])  # A列 - 源地址(可能是多个)
            dest_port_str = str(row['目的端口'])    # B列 - 目的地址和端口
            
            # 展开源IP地址
            source_ips = expand_ip_range(source_addr_str)
            
            # 展开端口
            dest_ports = expand_ports(dest_port_str)
            
            # 对每个源IP和每个端口组合进行测试
            for ip in source_ips:
                for port in dest_ports:
                    # 执行telnet连接测试
                    result = check_port_connectivity(ip, port)
                    
                    # 记录结果
                    results.append({
                        '目的地址': source_addr_str,
                        '目的端口': dest_port_str,
                        '网络验证的IP': ip,
                        '网络验证的Port': port,
                        '网络验证结果': result
                    })
                    
                    print(f"Testing: {ip}:{port} = {result}")
        
        # 创建结果DataFrame
        result_df = pd.DataFrame(results)
        
        # 保存结果到Excel文件
        output_file = f"{excel_file.split('.')[0]}_result_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx"
        result_df.to_excel(output_file, index=False)
        print(f"\n详细结果已保存到: {output_file}")
        
        # 生成汇总报告
        summary_data = []
        for index, row in df.iterrows():
            source_addr_str = str(row['目的地址'])
            dest_port_str = str(row['目的端口'])
            
            # 统计该行的所有测试结果
            row_results = [r for r in results 
                          if r['目的地址'] == source_addr_str and r['目的端口'] == dest_port_str]
            
            total_tests = len(row_results)
            success_count = sum(1 for r in row_results if r['网络验证结果'] == 'Success')
            
            if total_tests > 0:
                success_rate = f"{success_count}/{total_tests} ({success_count/total_tests*100:.1f}%)"
            else:
                success_rate = "No tests"
            
            summary_data.append({
                'A_Source': source_addr_str,
                'B_Destination': dest_port_str,
                'Success_Rate': success_rate
            })
        
        # 保存汇总结果到新文件而不是原文件
        summary_df = pd.DataFrame(summary_data)
        df['网络验证通过率'] = [item['Success_Rate'] for item in summary_data]
        
        # 保存更新后的文件到新文件名，避免权限冲突
        base_name = excel_file.split('.')[0]
        summary_file = f"{base_name}_summary_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx"
        df.to_excel(summary_file, index=False)
        print(f"汇总结果已保存到新文件: {summary_file}")
        
    except FileNotFoundError:
        print(f"错误: 找不到文件 {excel_file}")
    except PermissionError:
        print(f"错误: 没有权限写入文件 {excel_file}，请确保文件未被其他程序占用")
    except Exception as e:
        print(f"处理过程中发生错误: {str(e)}")
        import traceback
        traceback.print_exc()


# 使用示例
if __name__ == "__main__":
    # 替换为你的Excel文件路径
    excel_file_path = "d:/VSCodeProject/Python3/Network/network_check.xlsx"
    validate_network_from_excel(excel_file_path)
    """
    网络验证Excel文件应包含以下列:
    目的地址                         目的端口   
    192.168.1.11-20,192.168.1.100	80,443,8443	      
    10.0.0.1-10,10.0.0.50	        22,3306,6379	   
    """